package panda.cardutil.datamining;

import java.io.BufferedInputStream;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

import panda.client.enumerations.MagicSet;

/**
 * Creates a wget batch file to extract english magic:the gathering card scans from magiccards.info, a popular online
 * magic card database. Retrieves card (oracle) information from magiccards.info.
 * 
 * @author zane.tian@gmail.com
 */
public class MagiccardsInfoExtractor {
	static final boolean DEBUG = false;

	public static void main(String[] args) throws IOException {
		List<MagicSet> sets = new ArrayList<MagicSet>();
		MagiccardsInfoExtractor mie = new MagiccardsInfoExtractor();

		sets.add(MagicSet.M_10);

		for(MagicSet set : sets) {
			String setName = set.getName().replace(":", ""); /* fix for Ravnica since Windows doesn't allow ":" in filenames */
			writeBatchFile("C:\\" + setName + ".bat", set.getTotalCards(), set);
			// writeBatchFile("/Users/kyruru/Desktop/scripts/" + set.getAbbreviation() + ".sh", set.getTotalCards(), set);
			// mie.getCardInfo(set);
		}
	}

	/**
	 * Reads html files from magiccards.info online sequentially, obtaining card information (casting cost, card text,
	 * illustrator, flavor text, card type) from card numbers via http://magiccards.info/setName/en/n.html
	 * 
	 * @param set
	 */
	public void getCardInfo(MagicSet set) {
		String root = "http://magiccards.info/" + set.getAbbrev() + "/en/";
		StringBuffer buffer = new StringBuffer();

		URL link = null;
		try {
			for(int i = 1; i <= set.getTotalCards(); i++) {
				link = new URL(root + i + ".html");

				InputStream in = link.openStream();

				BufferedInputStream stream = new BufferedInputStream(in);
				Scanner scanner = new Scanner(stream, "UTF8");

				buffer = new StringBuffer();
				while(scanner.hasNext()) {
					String line = scanner.nextLine();
					buffer.append(line);
				}

				final String pageSrcWithTabs = buffer.toString();
				final String pageSrc = pageSrcWithTabs.replace("\t", "").replace("    ", "");
				final String nameSection = getCardNameSection(pageSrc, i);

				final String name = nameSection.substring(0, nameSection.indexOf("</a>"));

				if(DEBUG) {
					System.out.println("name: " + name + ".");
				}

				final String cardText = getCardText(nameSection);
				final String rarity = getRarity(pageSrc, set);

				/**
				 * <ul>
				 * <li>Creature - Angel 3/3, 4W (5)
				 * <li>Flying <i>(This creature can't be blocked except by creatures with flying.)</i>
				 * <li>When Angel of Mercy comes into play, you gain 3 life.
				 * <li><i>A song of life soars over fields of blood.</i>
				 * <li>Illus. Melissa A. Benson
				 * </ul>
				 * Splitting card text into components: The card text is split by "<br />" tags. The first line contains the
				 * casting cost (if the card isn't a land), the type, and the power + toughness if the card is a creature.
				 * The last line contains the illustrator's name, and the lines in between is the card's body text.
				 */
				final String[] split = cardText.split("<br />");

				final String typeLine = split[0];
				final String authorLine = split[split.length - 1];
				final String illustrator = authorLine.substring(authorLine.indexOf(' ') + 1);
				// gets rid of initial <br>
				final String bodyText = cardText.replace(typeLine, "").replace(authorLine, "").substring(6);

				if(DEBUG) {
					System.out.println("body text: " + bodyText + ".");
				}

				/**
				 * Casting cost and type: all found in the first line. Creature - Human Wizard 1/1, U (1)
				 */
				final int commaPosition;
				final String type;
				final String castingCost;

				if(typeLine.contains(",")) {
					commaPosition = typeLine.indexOf(',');
					type = typeLine.substring(0, commaPosition);
					castingCost = typeLine.substring(commaPosition + 2);
				} else {
					castingCost = "";
					type = typeLine;
				}

				if(DEBUG) {
					System.out.println("Casting Cost: " + castingCost + ".");
					System.out.println("Type: " + type + ".");
				}

				StringBuffer javaLine = new StringBuffer();
				javaLine.append("cards.add(new MagicCard(set, \"");
				javaLine.append(name + "\", ");
				javaLine.append("\"" + castingCost + "\", ");
				javaLine.append("\"" + type + "\", ");
				javaLine.append("\"" + bodyText.replace("\"", "\\\"") + "\", ");

				// javaLine.append("\"" + rarity + "\", ");
				if(rarity.equals("Land") || rarity.equals("Basic Land")) {
					javaLine.append("CardRarity.LAND, ");
				} else if(rarity.toLowerCase().equals("mythic rare")) {
					javaLine.append("CardRarity.MYTHIC, ");
				} else if(rarity.toLowerCase().equals("common")) {
					javaLine.append("CardRarity.COMMON, ");
				} else if(rarity.toLowerCase().equals("uncommon")) {
					javaLine.append("CardRarity.UNCOMMON, ");
				} else if(rarity.toLowerCase().equals("rare")) {
					javaLine.append("CardRarity.RARE, ");
				} else if(rarity.toLowerCase().equals("special")) {
					javaLine.append("CardRarity.SPECIAL, ");
				} else {
					throw new IllegalStateException("Incompatible rarity encountered: " + rarity + " from " + name);
				}

				javaLine.append("\"" + illustrator + "\", ");
				javaLine.append(i + "));");

				System.out.println(javaLine);

				in.close();
			}
		} catch(MalformedURLException e) {
			e.printStackTrace();
		} catch(IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Name: taken from search pattern <a href="/setAbbr/lang/n.html">Card Name</a>
	 */
	private String getCardNameSection(final String src, int cardIndex) {
		final String nDotHtml = cardIndex + ".html\">";
		final String nameSection = src.substring(src.indexOf(nDotHtml) + nDotHtml.length());

		return nameSection;
	}

	/**
	 * Card Text: taken from a div containing the card's name, casting cost, type, and text. Magiccards.info's format
	 * changes regularly. In April 15th 2008, find html paragraph delimiters and remove bold html, a style, and a
	 * possible oracle superscript link saying the text might have changed since the last oracle update.
	 */
	private String getCardText(final String nameSection) {
		final int cardTextBegin = nameSection.indexOf("<p>") + 3;
		final String cardTextSection = nameSection.substring(cardTextBegin);
		final int cardTextEnd = cardTextSection.indexOf("<p>");

		String cardTextDirty = cardTextSection.substring(0, cardTextEnd);
		cardTextDirty = cardTextDirty.replace("<b>", "").replace("</b>", "");
		cardTextDirty = cardTextDirty.replace("<b style=\"background: #feffc5;\">", "");
		cardTextDirty = cardTextDirty.replace("<sup><a href=\"#oracle\">1</a></sup>", "");
		final String cardText = cardTextDirty;

		if(DEBUG) {
			System.out.println("card text: " + cardText + ".");
		}

		return cardText;
	}

	/**
	 * Rarity: found in the listing of all sets where the current card appears in, such as in this example for Wand of
	 * Denial: 1. Classic Sixth Edition (R) 2. Visions (R). We get the rarity symbol from the correct set. pattern <td>
	 * <img src="/images/en.gif" /> Planar Chaos (Common)<br /> requires that pageSrc is cleared of tabs
	 */
	private String getRarity(final String pageSrc, MagicSet set) {
		final int rarityBegin = pageSrc.indexOf("/> " + set.getName() + " (") + set.getName().length() + 5;
		final String raritySection = pageSrc.substring(rarityBegin);
		final int rarityEnd = raritySection.indexOf(")");
		final String rarity = raritySection.substring(0, rarityEnd);

		if(DEBUG) {
			System.out.println("rarity: " + rarity + ".");
		}

		return rarity;
	}

	/**
	 * Outputs wget commands to a script file for all (totalCardsInSet) cards in the set. totalCardsInSet includes
	 * duplicates.
	 * 
	 * @param filename
	 * @param totalCardsInSet
	 * @param set
	 */
	public static void writeBatchFile(String filename, int totalCardsInSet, MagicSet set) {
		// final String wgetPrefix = "wget -P/Users/kyruru/Desktop/scans/";
		final String wgetPrefix = "C:\\GnuWin32\\bin\\wget -N -PC:\\magic\\";
		final String sitePrefix = "http://magiccards.info/scans/en/";

		try {
			BufferedWriter out = new BufferedWriter(new FileWriter(filename));
			for(int i = 0; i < totalCardsInSet; i++) {
				out.write(wgetPrefix + set.getAbbrev() + "\\ " + sitePrefix + set.getAbbrev() + "/" + (i + 1) + ".jpg");
				out.newLine();
			}

			out.close();
		} catch(IOException e) {
			e.printStackTrace();
		}

		if(DEBUG) {
			System.out.println(set + " complete! " + set.getTotalCards() + " cards processed");
		}
	}
}